package com.lzw.DailyAudit.service.dateAggregation_02.DailyAudit.service.dateAggregation_02;


import com.hooya.fa.eu.biz.DailyAudit.entity.DailyAuditStatus;
import com.hooya.fa.eu.biz.DailyAudit.entity.StkOrigDataCollect;
import com.hooya.fa.eu.biz.DailyAudit.entity.dto.B2cDataDTO;
import com.hooya.fa.eu.biz.DailyAudit.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class Insert_B2C {

    @Autowired
    private DailyTempXsjlMapper tempXsjlMapper;

    @Autowired
    private DailyPriceMapper priceMapper;

    @Autowired
    private DailyInvoiceMapper invoiceMapper;

    @Autowired
    private DailyBuyerMapper buyerMapper;

    @Autowired
    private CommonService commonService;


	@Autowired
	private DailyAuditStatusMapper statusMapper;


	public void insert_b2c(String currentDate) {
		try {

			String name = "insertB2c-02";
			DailyAuditStatus dailyAuditStatus = statusMapper.selectStatus(name, currentDate);
			if(dailyAuditStatus != null && dailyAuditStatus.getFlag() == 1){
				log.info("{} - 该方法已执行，进行跳过！",name);
				return;
			}

            log.info("开始执行Insert_B2C，日期为：{}", currentDate);

            // 获取主要数据--根据日期范围查询B2C销售数据
            List<B2cDataDTO> mainData = tempXsjlMapper.getXsjlB2CData(currentDate); // fa_eu.temp_xsjl

            // 获取价格数据
            List<B2cDataDTO> plnPriceData = priceMapper.getPlnPriceData(); // europe.price_pln
            plnPriceData.forEach(data -> data.setNumber(data.getNumber().split("\\.")[0])); //如果有小数，曲奇前面的整数
            
            // 创建PLN价格映射，避免重复处理
            Map<String, List<B2cDataDTO>> plnPriceMap = plnPriceData.stream()
                    .collect(Collectors.groupingBy(B2cDataDTO::getNumber));
            
            // 先处理PLN价格数据，减少后续处理的数据量
            List<B2cDataDTO> mainDataWithPlnPrice = processPlnPrice(mainData, plnPriceMap);

			// 拆分有价格和无价格的数据
			Map<Boolean, List<B2cDataDTO>> pricePartition = mainDataWithPlnPrice.stream().collect(Collectors.partitioningBy(dto -> dto.getPrice() != null));
			List<B2cDataDTO> withPlnPrice = pricePartition.get(true);
			withPlnPrice.forEach(item -> item.setCurrency("PLN"));
			List<B2cDataDTO> withoutPriceData = pricePartition.get(false);

			// 清理不再使用的集合
			clearAndNullify(mainData,plnPriceData,mainDataWithPlnPrice);

            // 处理EUR价格数据 - 使用更小的批次大小
            String lastSheetNumber = null;
            boolean hasMoreData = true;
            int batchSize = 500000; // 减小批次大小，降低内存压力
            List<B2cDataDTO> eurPriceResults = new ArrayList<>();
            
            while (hasMoreData) {
                log.info("开始查询EUR价格数据批次，lastSheetNumber: {}", lastSheetNumber);
                
                // 查询当前批次的EUR价格数据
                List<B2cDataDTO> eurPriceData = priceMapper.getEurPriceDataByOrderIdRange(lastSheetNumber, batchSize);  //europe.price_eur
                
                if (eurPriceData.size() < batchSize) {
                    hasMoreData = false;
                }

                if (!eurPriceData.isEmpty()) {
                    // 去重优化：直接使用LinkedHashMap保持插入顺序，避免多次Stream操作
                    Map<String, B2cDataDTO> uniqueMap = new LinkedHashMap<>();
                    for (B2cDataDTO item : eurPriceData) {
                        String key = item.getOrderid() + "|" + item.getCpbh();
                        uniqueMap.putIfAbsent(key, item); // 保留第一个出现的
                    }
                    
                    // 清理原始数据
                    eurPriceData.clear();
                    
                    // 转换为有序列表
                    List<B2cDataDTO> uniqueEurData = new ArrayList<>(uniqueMap.values());
                    uniqueEurData.sort(Comparator.comparing(B2cDataDTO::getSheetnumber));
                    
                    // 处理当前批次的EUR价格数据
                    processEurPriceBatch(withoutPriceData, uniqueEurData, eurPriceResults);
                    
                    // 更新lastSheetNumber
                    lastSheetNumber = uniqueEurData.get(uniqueEurData.size() - 1).getSheetnumber();
                    log.info("EUR价格数据批次处理完成，当前批次数量：{}，最后一个sheetNumber：{}", 
                            uniqueEurData.size(), lastSheetNumber);
                    
                    // 清理当前批次的数据
                    uniqueMap.clear();
                    uniqueEurData.clear();
                    
                    // 提示JVM进行垃圾回收
                    System.gc();
                }
                
                // 清理当前批次数据
                eurPriceData.clear();
                eurPriceData = null;
            }
            

            List<B2cDataDTO> finalPriceData = new ArrayList<>(withPlnPrice);
            finalPriceData.addAll(eurPriceResults);
            finalPriceData.addAll(withoutPriceData);

            // 添加发票和买家信息
            List<B2cDataDTO> buyerMerge = addInvoiceAndBuyer(finalPriceData);

			// 清理不再使用的集合
			clearAndNullify(withPlnPrice,withoutPriceData,eurPriceResults,finalPriceData);

            // 校验数据
            commonService.dataVerificationB2c(buyerMerge);

			// 拆分有价格和无价格的数据
			Map<Boolean, List<B2cDataDTO>> pricePartitionTwo = buyerMerge.stream().collect(Collectors.partitioningBy(dto -> dto.getPrice() != null));
			List<B2cDataDTO> finalWithPrice = pricePartitionTwo.get(true);
			List<B2cDataDTO> finalWithoutPrice = pricePartitionTwo.get(false);
            log.info("B2C数据拆分完成，有价格数据：{} 条，无价格数据：{} 条", finalWithPrice.size(), finalWithoutPrice.size());

            // 转换为实体类并保存
            List<StkOrigDataCollect> withPriceRecords = commonService.convertB2cToStkOrigDataCollect(finalWithPrice, true);
            List<StkOrigDataCollect> withoutPriceRecords = commonService.convertB2cToStkOrigDataCollect(finalWithoutPrice, false);

            commonService.batchInsert(withPriceRecords);
            commonService.batchInsert(withoutPriceRecords);

			// 修改执行状态
			commonService.UpdateOrInsertStatus(dailyAuditStatus, name, currentDate);

			log.info("insertB2C 执行完成");
        } catch (Exception e) {
            log.error("处理B2C数据失败", e);
            throw new RuntimeException("处理B2C数据失败", e);
        }
    }

	/**
	 * 清理并置空集合对象
	 * @param collections 可变参数，需要清理的集合对象
	 */
	@SafeVarargs
	private final void clearAndNullify(List<B2cDataDTO>... collections) {
		for (List<B2cDataDTO> collection : collections) {
			if (collection != null) {
				collection.clear();
				collection = null;
			}
		}
	}

    /**
     * 处理PLN价格数据
     */
    private List<B2cDataDTO> processPlnPrice(List<B2cDataDTO> mainData, Map<String, List<B2cDataDTO>> plnPriceMap) {
        log.info("开始处理PLN价格数据");
        List<B2cDataDTO> result = new ArrayList<>(mainData.size()); // 预先分配容量
        
        for (B2cDataDTO mainItem : mainData) {
            String key = mainItem.getSheetnumber();
            if (plnPriceMap.containsKey(key)) {
                List<B2cDataDTO> priceItems = plnPriceMap.get(key);
                for (B2cDataDTO priceItem : priceItems) {
                    B2cDataDTO newItem = new B2cDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setPrice(priceItem.getPrice());
                    result.add(newItem);
                }
            } else {
                result.add(mainItem);
            }
        }
        
        log.info("PLN价格数据处理完成，共处理 {} 条数据", result.size());
        return result;
    }
    
    /**
     * 处理EUR价格数据批次
     */
    private void processEurPriceBatch(List<B2cDataDTO> withoutPriceData, List<B2cDataDTO> eurPriceData, List<B2cDataDTO> results) {
        // 构建EUR价格映射
        Map<String, List<B2cDataDTO>> eurPriceMap = new HashMap<>(eurPriceData.size());
        for (B2cDataDTO eurItem : eurPriceData) {
            String key = eurItem.getOrderid() + "|" + eurItem.getCpbh();
            eurPriceMap.computeIfAbsent(key, k -> new ArrayList<>()).add(eurItem);
        }
        
        // 临时存储本轮处理结果
        List<B2cDataDTO> batchResults = new ArrayList<>();
        List<B2cDataDTO> stillWithoutPrice = new ArrayList<>();
        
        for (B2cDataDTO withoutPriceItem : withoutPriceData) {
            String key = withoutPriceItem.getOrderid() + "|" + withoutPriceItem.getCpbh();
            if (eurPriceMap.containsKey(key)) {
                List<B2cDataDTO> eurItems = eurPriceMap.get(key);
                for (B2cDataDTO eurItem : eurItems) {
                    B2cDataDTO newItem = new B2cDataDTO();
                    BeanUtils.copyProperties(withoutPriceItem, newItem);
                    newItem.setPrice(eurItem.getPrice());
                    newItem.setCurrency("EUR");
                    batchResults.add(newItem);
                }
            } else {
                stillWithoutPrice.add(withoutPriceItem);
            }
        }
        
        // 将批次结果添加到总结果中
        results.addAll(batchResults);
        
        // 更新withoutPriceData（只保留仍无价格的数据）
        withoutPriceData.clear();
        withoutPriceData.addAll(stillWithoutPrice);
        
        // 清理中间数据
        batchResults.clear();
        stillWithoutPrice.clear();
        eurPriceMap.clear();
    }

    /**
     * 添加发票和买家信息
     */
    private List<B2cDataDTO> addInvoiceAndBuyer(List<B2cDataDTO> finalPriceData) {
        log.info("开始添加B2C发票和买家信息");

        // 获取发票数据 - 分批处理发票数据
        List<B2cDataDTO> invoiceMerge = processInvoiceData(finalPriceData);
        
        // 清理finalPriceData，因为不再需要
        finalPriceData.clear();
        finalPriceData = null;
        
        // 获取买家数据 - 使用更小的批次大小
        List<B2cDataDTO> buyerMerge = processBuyerData(invoiceMerge);
        
        // 清理invoiceMerge
        invoiceMerge.clear();
        invoiceMerge = null;
        
        log.info("添加B2C发票和买家信息完成，共处理 {} 条数据", buyerMerge.size());
        return buyerMerge;
    }
    
    /**
     * 处理发票数据
     */
    private List<B2cDataDTO> processInvoiceData(List<B2cDataDTO> finalPriceData) {
        // 分批获取发票数据，避免一次性加载大量数据
        // 这里可以根据实际情况调整批次大小或实现真正的分批查询
        List<B2cDataDTO> invoiceB2cData = invoiceMapper.getB2cInvoiceData();
        
        // 构建发票数据映射
        Map<String, List<B2cDataDTO>> invoiceB2cDataMap = new HashMap<>(invoiceB2cData.size());
        for (B2cDataDTO invoiceItem : invoiceB2cData) {
            String key = invoiceItem.getOrderid() != null ? invoiceItem.getOrderid() : "null";
            invoiceB2cDataMap.computeIfAbsent(key, k -> new ArrayList<>()).add(invoiceItem);
        }
        
        // 处理发票数据
        List<B2cDataDTO> invoiceMerge = new ArrayList<>(finalPriceData.size());
        for (B2cDataDTO mainItem : finalPriceData) {
            String key = mainItem.getOrderid();
            if (invoiceB2cDataMap.containsKey(key)) {
                List<B2cDataDTO> matchingInvoices = invoiceB2cDataMap.get(key);
                for (B2cDataDTO invoiceItem : matchingInvoices) {
                    B2cDataDTO newItem = new B2cDataDTO();
                    BeanUtils.copyProperties(mainItem, newItem);
                    newItem.setHthm(invoiceItem.getHthm());
                    invoiceMerge.add(newItem);
                }
            } else {
                invoiceMerge.add(mainItem);
            }
        }
        
        // 清理中间数据
        invoiceB2cData.clear();
        invoiceB2cDataMap.clear();
        
        return invoiceMerge;
    }
    
    /**
     * 处理买家数据
     */
    private List<B2cDataDTO> processBuyerData(List<B2cDataDTO> invoiceMerge) {
        List<B2cDataDTO> tempInvoiceMerge = new ArrayList<>(invoiceMerge);
        String lastSheetNumber = null;
        boolean hasMoreData = true;
        int batchSize = 2100000; // 减小批次大小，降低内存压力

        while (hasMoreData) {
            List<B2cDataDTO> batchBuyerData = buyerMapper.batchGetB2cBuyer(lastSheetNumber, batchSize);

            if (batchBuyerData.size() < batchSize) {
                hasMoreData = false;
            }
            
            if (!batchBuyerData.isEmpty()) {
                // 手动去重，避免多次Stream操作
                Map<String, B2cDataDTO> uniqueMap = new LinkedHashMap<>();
                for (B2cDataDTO item : batchBuyerData) {
                    String key = item.getSheetnumber() + "|" + item.getTocompany();
                    uniqueMap.putIfAbsent(key, item); // 保留第一个出现的元素
                }
                
                // 转换为有序列表
                List<B2cDataDTO> uniqueBuyerData = new ArrayList<>(uniqueMap.values());
                uniqueBuyerData.sort(Comparator.comparing(B2cDataDTO::getSheetnumber));
                
                // 更新lastSheetNumber
                lastSheetNumber = uniqueBuyerData.get(uniqueBuyerData.size() - 1).getSheetnumber();
                log.info("分批获取B2C买家数据，当前批次数量：{}，最后一个sheetNumber：{}", 
                        uniqueBuyerData.size(), lastSheetNumber);

                // 构建买家数据映射
                Map<String, List<B2cDataDTO>> buyerDataMap = new HashMap<>(uniqueBuyerData.size());
                for (B2cDataDTO buyerItem : uniqueBuyerData) {
                    buyerDataMap.computeIfAbsent(buyerItem.getSheetnumber(), k -> new ArrayList<>()).add(buyerItem);
                }
                
                // 处理当前批次的买家数据
                List<B2cDataDTO> buyerMerge = new ArrayList<>(tempInvoiceMerge.size());
                for (B2cDataDTO invoiceItem : tempInvoiceMerge) {
                    String key = invoiceItem.getSheetnumber();
                    if (buyerDataMap.containsKey(key)) {
                        List<B2cDataDTO> matchingBuyers = buyerDataMap.get(key);
                        for (B2cDataDTO buyerItem : matchingBuyers) {
                            B2cDataDTO newItem = new B2cDataDTO();
                            BeanUtils.copyProperties(invoiceItem, newItem);
                            newItem.setTocompany(buyerItem.getTocompany());
                            buyerMerge.add(newItem);
                        }
                    } else {
                        buyerMerge.add(invoiceItem);
                    }
                }
                
                // 更新临时列表
                tempInvoiceMerge = buyerMerge;
                
                // 清理中间数据
                uniqueMap.clear();
                uniqueBuyerData.clear();
                buyerDataMap.clear();
                batchBuyerData.clear();
                
                // 提示JVM进行垃圾回收
                System.gc();
            }
        }

        List<B2cDataDTO> buyerMerge = new ArrayList<>(tempInvoiceMerge);
        log.info("添加B2C发票和买家信息完成，共处理 {} 条数据", buyerMerge.size());

        return buyerMerge;
    }


}